package reflect;

import java.io.File;
import java.lang.reflect.Method;

/**
 * 练习，使用反射有选择的自动调用一个类中的部分方法
 *
 * 1:定义一个注解:@AutoRun  作用在方法上，作用范围为运行时
 * 2:定义一个类:Foo
 *   Foo中有10个方法，A(),B(),C(),....  方法内部输出A，B，C..
 * 3:当我们指向利用反射机制自动调用其中的部分方法时，可以在对应方法上使用注解
 *   @AutoRun,例如，给A(),C(),G(),I()这四个方法添加注解，其余不加
 * 4:在下面的main方法中做如下操作:
 *   4.1:加载Foo类对象，并实例化
 *   4.2:获取Foo中定义的所有方法
 *   4.3:遍历每一个方法，并判断是否有注解:
 *   4.4:有该注解的则利用反射执行该方法。
 *
 *
 * 让reflect包下Person类和Foo类中的部分方法自动调用?
 * 定义一个注解:@AutoRunClass 作用于类上。(ElementType.TYPE)
 * 只有reflect包下包含该注解的类才是我们需要反射并自动调用其中方法的类。
 *
 *  通过该练习，我们得知，实际开发中，我们可以使用注解辅助反射机制筛选需要操作的
 *  类或方法或属性等。减少不必要的操作和开销。
 *
 */
public class Test {
    public static void main(String[] args) throws Exception {
        //获取类所在的包，通常的方式是通过类路径完成，这样的做法是最通用的

        //idea开发环境定位某个类所在的包给定的路径，不完全通用
//        File dir = new File("./src/main/java/包路径");

        //使用类路径最通用，无所谓程序的运行环境是什么(idea,eclipse,tomcat等)

        /*
            飞机大战中，首次使用了类路径作为相对路径定位内容:
             FlyingObject.class.getResource(fileName)

             格式:
             某个类的类名.class.getResource(文件名)
             这里指定的文件相对的目录是当前类所在的目录

         */
        /*
            JVM运行的是字节码文件!
            idea会将源代码，idea项目目录/src/main/java中的所有包和所有.java文件进行编译
            并存放在:idea项目目录/target/classes/所有的包和.class文件

            JVM执行当前Test类时，对应的路径是:
            idea项目目录/target/classes/reflect/Test.class

            Test.class.getResource所对的当前目录就是当前Test所在的目录

            下面的代码定位的是:
            idea项目目录/target/classes/reflect/Student.class
         */
        File file = new File(Test.class.getResource("Student.class").toURI());
        System.out.println(file);


        /*
            需求是读取不和当前类在同一个目录(包)下的其他资源时如何定位?
            使用类加载器，它可以定位到当前项目中所有类所在的根目录(类路径的根，即
            当前项目中，所有包的最上级)


            Test.class.getClassLoader().getResource()
            所对的目录:类路径的根
            idea项目目录/target/classes/

            定位io包下的BOSDemo.class
            idea项目目录/target/classes/我们写的代码所对应的包/所对应的类的class文件
            Test.class.getClassLoader().getResource("io/BOSDemo.class")
         */
        File file1 = new File(Test.class.getClassLoader().getResource("io/BOSDemo.class").toURI());
        System.out.println(file1);




        File dir = new File(Test.class.getClassLoader().getResource("reflect").toURI());
        //获取所有的class文件
        File[] subs = dir.listFiles(
                f->f.getName().endsWith(".class")
        );

        //遍历每个文件并获取类名
        for(File classFile : subs){
            String className = classFile.getName().substring(0,classFile.getName().lastIndexOf("."));

            Class cls = Class.forName("reflect."+className);
            if(cls.isAnnotationPresent(AutoRunClass.class)) {
                Object o = cls.newInstance();
                Method[] methods = cls.getDeclaredMethods();
                for (Method m : methods) {
                    if (m.isAnnotationPresent(AutoRun.class)) {
                        m.invoke(o);
                    }
                }
            }
        }


    }
}
